#include <main.h>
#include <video.h>
#include <arch.h>
#include <types.h>
#include <syscall.h>
#include <task/task.h>
#include <fs/fs.h>
#include <network/network.h>
#include <mm.h>
#include <debug.h>
#include <util.h>
#include <driver.h>
#include <bish.h>
#include <config.h>
#include <driver/video/vesa.h>
#include <screenpig/main.h>


/**
 * Carica il sistema
 *
 * \param mb puntatore al multiboot header
 */
int main(multiboot_info_t *mb)
{
	#ifdef DEBUG
		debug_init();
		#ifdef DEBUG_REG_TRAC
			debug_reg_trace(1);
		#endif
	#endif
	
	
	DEBUGP("main()\n");

	mod_addr = (void *) ((multiboot_module_t *) mb->mods_addr)->mod_start;


	video_set_color(VIDEO_HI_WHITE_BLACK);
	video_clear();
	
	video_puts_colored(VIDEO_HI_BLUE_BLACK, "-> ");
	video_puts_colored(VIDEO_HI_BLUE_BLACK, MSG_WELCOME);
	video_puts_colored(VIDEO_HI_BLUE_BLACK, NAME);
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " ");
	video_puts_colored(VIDEO_HI_BLUE_BLACK, VER);
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " ");
	video_puts_colored(VIDEO_HI_BLUE_BLACK, REV);
	video_puts("\n");
	
	
	// Arch based
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
	video_puts(MSG_ARCH_INIT);
	arch_init();
	printf("%s (%s)\n", ARCH, CPU_VENDOR);
	
	// Memory manager
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
	video_puts(MSG_MM_INIT); 
	mm_init(mb->mem_lower, mb->mem_upper);
	video_puts("(");
	video_putint((mm_get_total_mem() / 1024));
	video_puts("mb)\n");
	
	// Driver manager
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
	video_puts(MSG_DRV_INIT); 
	driver_init();
		
	// Syscalls
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
	video_puts(MSG_SYSCALL_INIT);
	syscall_init();

	// Task Manager
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
	video_puts(MSG_TASK_INIT);	
	task_init(TASK_SWITCH_ROUND_ROBIN);	
	
	
	// Controlliamo prima se e' possibile avviare la gui
	#ifdef DVESA
		if(mb->vbe_control_info != 0)
		{		
			vesa_init(mb->vbe_control_info, mb->vbe_mode_info);
			DEBUGP("vesa mode\n");
			
			// Avviamo screenpig
			#ifdef SCREENPIG
				if(mb->vbe_control_info != 0)
				{
					screen_pig_loading(vesa_get_mode_info()->width, vesa_get_mode_info()->height);
					screen_pig_main(vesa_get_mode_info()->width, vesa_get_mode_info()->height);
					goto sd;
				}
			#endif
		}
	#endif
	
	
	// File System Manager
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
	video_puts(MSG_FS_INIT);	
	fs_init();

	// Update hardware
	device_update();
	
	#ifdef NETWORK
		// Network Manager
		video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
		video_puts(MSG_NET_INIT);	
		network_init();
	#endif
	
	char *asd[1] = {"system"};
	char *asd2[1] = {"test"};  
	task_exec(task2, asd, 1);
	task_exec(task1, asd2, 1);
	
	//term_delete(task_get_from_pid(1)->term);
	
	// Se e' definita la shell, carichiamola
	#ifdef SHELL
		bish();
		goto sd;
	#endif


	// Spegnimento se init viene chiuso
	sd:
		shutdown();
		
		while(1);
}


/**
 * Spegnimento del pc
 */
void shutdown()
{	
	DEBUGP("shutdown()\n");
	
	printf("\n");
	
	// Mandiamo il segnale di kill a tutti i processi
	/*DEBUGP("main.c -> killing all processes\n");*/
	video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
	video_puts(MSG_TASK_KILL);
	task_kill(0);
	
	
	// Umount di tutti i filesystem
	mount_point_t *a;
	mount_point_t *mp = fs_mountpoints;
	while(mp != NULL)
	{
		a = mp->next;
		video_puts_colored(VIDEO_HI_BLUE_BLACK, " -> ");
		printf(MSG_UMOUNTING " %s\n", mp->path);
		fs_umount(mp->path);
		mp = a;
	}
	
	// Fermiamo gli interrupt
	//video_puts("\n");
	asm("cli");
	
	
	video_puts_colored(VIDEO_HI_BLUE_BLACK, "-> ");		
	video_puts(MSG_SHUTDOWN);
	
	// Fermiamo la cpu
	asm("hlt");
	
	while(1);
}
